package top.bug.blog.utils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import eu.bitwalker.useragentutils.*;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @author <a href="https://github.com/jiusi66">九思.</a>
 * @email 10837907@qq.com
 * @from <a href="https://www.52bug.top">递归茶馆-www.52bug.top</a>
 * @description UserAgent解析工具类
 */
@Component
@Slf4j
public class UserAgentUtil {

    /**
     * 解析UserAgent字符串，获取客户端信息
     */
    public static ClientInfo parseUserAgent(String userAgentString) {
        if (StringUtils.isBlank(userAgentString)) {
            return ClientInfo.unknown();
        }

        try {
            UserAgent userAgent = UserAgent.parseUserAgentString(userAgentString);
            Browser browser = userAgent.getBrowser();
            OperatingSystem os = userAgent.getOperatingSystem();

            return ClientInfo.builder()
                    .browser(browser.getName())
                    .browserVersion(getBrowserVersion(userAgent))
                    .browserType(browser.getBrowserType().getName())
                    .operatingSystem(os.getName())
                    .deviceType(getDeviceType(os))
                    .deviceFamily(os.getGroup().getName())
                    .manufacturer(os.getManufacturer().getName())
                    .build();

        } catch (Exception e) {
            log.warn("UserAgent解析失败: {}, 原始字符串: {}", e.getMessage(), userAgentString);
            return ClientInfo.unknown();
        }
    }

    /**
     * 从HttpServletRequest解析客户端信息
     */
    public static ClientInfo parseFromRequest(HttpServletRequest request) {
        String userAgentString = request.getHeader("User-Agent");
        String clientIP = getClientIP(request);

        ClientInfo clientInfo = parseUserAgent(userAgentString);
        clientInfo.setIpAddress(clientIP);

        return clientInfo;
    }

    /**
     * 获取浏览器版本
     */
    private static String getBrowserVersion(UserAgent userAgent) {
        Version version = userAgent.getBrowserVersion();
        return version != null ? version.getVersion() : "Unknown";
    }

    /**
     * 获取设备类型
     */
    private static String getDeviceType(OperatingSystem os) {
        DeviceType deviceType = os.getDeviceType();
        if (deviceType != null) {
            return deviceType.getName();
        }
        return "Unknown";
    }

    /**
     * 获取客户端真实IP
     */
    private static String getClientIP(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个IP值，第一个为真实IP
            int index = ip.indexOf(',');
            if (index != -1) {
                return ip.substring(0, index);
            }
            return ip;
        }

        ip = request.getHeader("X-Real-IP");
        if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }

        return request.getRemoteAddr();
    }

    /**
     * 客户端信息封装类
     */
    @Data
    @Builder
    public static class ClientInfo {
        private String browser;
        private String browserVersion;
        private String browserType;
        private String operatingSystem;
        private String deviceType;
        private String deviceFamily;
        private String manufacturer;
        private String ipAddress;

        public static ClientInfo unknown() {
            return ClientInfo.builder()
                    .browser("Unknown")
                    .browserVersion("Unknown")
                    .browserType("Unknown")
                    .operatingSystem("Unknown")
                    .deviceType("Unknown")
                    .deviceFamily("Unknown")
                    .manufacturer("Unknown")
                    .ipAddress("0.0.0.0")
                    .build();
        }

        /**
         * 标准化设备类型（pc/mobile/tablet）
         */
        public String getStandardDeviceType() {
            if (deviceType.contains("Computer") || "PC".equals(deviceType)) {
                return "pc";
            } else if (deviceType.contains("Mobile")) {
                return "mobile";
            } else if (deviceType.contains("Tablet")) {
                return "tablet";
            }
            return "unknown";
        }
    }
}